// ignore_for_file: use_build_context_synchronously

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dnsolve/dnsolve.dart';
import 'package:xvideos/hj_utils/text_util.dart';
import 'package:xvideos/tools_base/debug_log.dart';

import '../config/config.dart';
import '../tools_base/net/base_resp_bean.dart';
import '../tools_base/net/net_manager.dart';

/// 选线工具第三版本,约会和vpn基本统一
/// 主要修改pingcheck的地址
class DetectLineManager {
  final Dio _dio = createDio();

  // 取消列表
  final _cancelList = <CancelToken>[];

  Future<String> detectLineOnce() async {
    var line = await _detectLineOnce();
    if (TextUtil.isNotEmpty(line)) {
      for (var it in _cancelList) {
        it.cancel();
      }
      _cancelList.clear();
      return line;
    }

    return line;
  }

  /// 一次完整的批量选线过程
  Future<String> _detectLineOnce() async {
    ///线路组装
    List<String> lines = [];
    lines.addAll(Config.LINE_LIST);
    String successLine = await _pingCheckPatch(lines);
    //此时已失败,使用本地备用线路
    if (TextUtil.isEmpty(successLine)) {
      successLine = await dnsSolve();
    }

    return successLine;
  }

  //本地域名不通的情况下，使用dns解析
  Future<String> dnsSolve() async {
    final dnsolve = DNSolve();
    final response = await dnsolve.lookup(
      'hjll.domainapis.com',
      dnsSec: true,
      type: RecordType.txt,
    );

    if (response.answer!.records != null) {
      for (final record in response.answer!.records!) {
        if (record.data.isNotEmpty) {
          print('dnsSolve ==== ${record.data}');
          return record.data;
        }
      }
    }
    return '';
  }

  ///检查一批线路
  Future<String> _pingCheckPatch(List<String> lines) async {
    if (lines.isEmpty) return "";
    //开启一连串异步任务
    Completer<String> completer = Completer();
    var listFuture = <Future<bool>>[];
    List<String> pingOKList = [];

    Future.forEach(lines, (element) {
      if (TextUtil.isNotEmpty(element)) {
        listFuture.add((String s) async {
          debugLog("selectLine", "pingCheck() _selectLineOnce()...开始选线:$s");
          var cancelToken = CancelToken();
          _cancelList.add(cancelToken);
          var suc = _pingCheck(s, cancelToken);
          _cancelList.remove(cancelToken);
          if (await suc) {
            if (completer.isCompleted) {
              pingOKList.add(s);
            } else {
              debugLog("selectLine", "pingCheck() _selectLineOnce()...选线成功:$s");
              completer.complete(s);
            }
          } else {
            debugLog("selectLine", "pingCheck() _selectLineOnce()...线路不可用:$s");
          }
          return suc;
        }(element));
      }
    });

    Future.wait<bool>(listFuture).whenComplete(() {
      if (completer.isCompleted) {
        debugLog("selectLine", "_selectLineOnce()...is already success}");
        return;
      }
      if (pingOKList.isNotEmpty) {
        debugLog("selectLine", "_selectLineOnce()...选线成功:${pingOKList[0]}");
        completer.complete(pingOKList[0]);
      } else {
        debugLog("selectLine", "_selectLineOnce()...not avalible line}");
        completer.complete("");
      }
    }); // 异步
    return completer.future;
  }

  /// 单次网络请求
  Future<bool> _pingCheck(String line, [CancelToken? cancelToken]) async {
    Response? resp;
    DateTime startTime = DateTime.now();
    String path = "/api/app/ping/check";
    try {
      // String path = "/api/pingCheck";

      String method = "GET";

      resp = await _dio.request(
        line + path,
        options: Options(
          method: method,
          sendTimeout: const Duration(seconds: 10),
          receiveTimeout: const Duration(seconds: 10),
          headers: {
            // "token": await netManager.getToken(),
            // "User-Agent": await netManager.userAgent(),
            // "x-api-key": await netManager.sign(path, method, {}),
          },
        ),
        cancelToken: cancelToken,
      );
    } catch (e) {
      debugLog("ping", "pingCheck()...error:$e");
      //showToast( "ping失败1" + e.toString());
    }

    debugLog("ping", "pingCheck()...line:$line cost ${DateTime.now().difference(startTime).inMilliseconds} milSeconds");

    if (null == resp || resp.statusCode != HttpStatus.ok) {
      debugLog("ping", "pingCheck()...resp is null or code:${resp?.statusCode}");
      return false;
    }
    BaseRespBean? baseResp;
    if (resp.data is Map) {
      baseResp = BaseRespBean.fromJson(resp.data);
      //showToast( "ping成功1" + (line + path).toString());
    } else if (resp.data is String) {
      baseResp = BaseRespBean.fromJson(json.decode(resp.data));
      //showToast( "ping成功2" + (line + path).toString());
    }
    if (TextUtil.isNotEmpty(baseResp?.time)) {
      netManager.setServerTime(baseResp?.time);
    }

    // 业务码200才算成功
    return baseResp?.code == HttpStatus.ok;
  }

  /// 单次网络请求
  Future<String> getDnsAddress(String path, [CancelToken? cancelToken]) async {
    Response? resp;
    Dio dio = createDio(); //获取DNS，用单独的网络请求
    try {
      resp = await dio.request(
        path,
        options: Options(
            method: 'GET',
            headers: <String, dynamic>{},
            responseType: ResponseType.plain,
            receiveTimeout: const Duration(seconds: 5),
            sendTimeout: const Duration(seconds: 5)),
      );
    } catch (e) {
      debugLog("ping", "pingCheck()...error:$e");
    }
    debugLog("resp", "resp..error:${resp?.toString()}");
    if (null == resp || resp.statusCode != HttpStatus.ok) {
      debugLog("ping", "pingCheck()...resp is null or code:${resp?.statusCode}");
      return "";
    }
    BaseRespBean? baseResp;
    if (resp.data is Map) {
      baseResp = BaseRespBean.fromJson(resp.data);
    } else if (resp.data is String) {
      baseResp = BaseRespBean.fromJson(json.decode(resp.data));
    }
    return baseResp?.data;
  }
}
